package org.lhg.activiti.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;

import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;

import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.javax.el.ExpressionFactory;
import org.activiti.engine.impl.javax.el.ValueExpression;
import org.activiti.engine.impl.juel.ExpressionFactoryImpl;
import org.activiti.engine.impl.juel.SimpleContext;

import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.PvmActivity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;

import org.lhg.activiti.model.MyComment;
import org.lhg.activiti.model.MyTask;
import org.lhg.activiti.model.PageBean;
import org.lhg.activiti.service.UserService;
import org.lhg.activiti.util.CommonResult;
import org.lhg.activiti.util.ElUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;


import java.util.*;


@RestController
@RequestMapping("/task")
public class TaskController {
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private HistoryService historyService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private UserService userService;

    /**
     * 待办任务
     * @param page
     * @param limit
     * @param userId
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/listTask",method = RequestMethod.GET)
    public CommonResult<JSONObject> listTask(@RequestParam(value="page",defaultValue="0")String page, @RequestParam(value="limit",defaultValue="0")String limit, String userId)throws Exception{
        PageBean pageBean=new PageBean(Integer.parseInt(page),Integer.parseInt(limit));
        // 返回带分页的结果集合
        List<Task> list=taskService.createTaskQuery().orderByTaskCreateTime().desc().taskAssignee(userId).listPage(pageBean.getStart(), pageBean.getPageSize());
        List<MyTask> taskList=new ArrayList<MyTask>();
        Map<String,String> userMap=userService.getUserList();
        Map<String, String>modelMap=getModelList();

        for(Task t:list){
            MyTask myTask=new MyTask();
            myTask.setId(t.getId());
            myTask.setProcessInstanceId(t.getProcessInstanceId());
            myTask.setProcdef_id(t.getProcessDefinitionId());
            myTask.setName(t.getName());
            myTask.setCreateTime(t.getCreateTime());
            myTask.setUserName(userMap.get(t.getAssignee()));
            myTask.setModelName(modelMap.get(t.getProcessDefinitionId().split(":")[0]));
            taskList.add(myTask);
        }
        long total=taskService.createTaskQuery().taskAssignee(userId).count(); // 获取总记录数

        JSONObject result=new JSONObject();
        JSONArray jsonArray=JSONArray.parseArray(JSON.toJSONString(taskList));
        result.put("rows", jsonArray);
        result.put("total", total);
        return CommonResult.success(result);
    }

    /**
     * 查询当前流程图
     * @param map
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/showCurrentView",method = RequestMethod.POST)
    public CommonResult<JSONObject> showCurrentView(@RequestBody Map<String,Object> map) throws Exception {
        String taskId=map.get("taskId").toString();
        String selectId=map.get("selectId").toString();
        String processDefinitionId=null;
        String processInstanceId=null;
        switch (selectId){
            case "1":
                // 根据任务id查询
                Task task=taskService.createTaskQuery().taskId(taskId).singleResult();
                // 获取流程定义id
                processDefinitionId=task.getProcessDefinitionId();
                // 获取流程实例id
                processInstanceId=task.getProcessInstanceId();
                break;
            case "2":
                HistoricTaskInstance hti=historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
                processDefinitionId=hti.getProcessDefinitionId();
                processInstanceId=hti.getProcessInstanceId();
                break;
            default:
                break;
        }
        // 根据流程定义id查询
        ProcessDefinition processDefinition=repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
        JSONObject result=new JSONObject();
        // 部署id
        result.put("deploymentId",processDefinition.getDeploymentId());
        // 图片资源文件名称
        result.put("diagramResourceName", processDefinition.getDiagramResourceName());
        ProcessDefinitionEntity processDefinitionEntity=(ProcessDefinitionEntity) repositoryService.getProcessDefinition(processDefinitionId);

        // 根据流程实例id获取流程实例
        ProcessInstance pi=runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        // 根据活动id获取活动实例
        ActivityImpl activityImpl=processDefinitionEntity.findActivity(pi.getActivityId());
        List<Map<String,Object>> currentList = new ArrayList<Map<String,Object>>();
        Map<String,Object> currentMap=null;
        if("parallelGateway".equals(activityImpl.getProperty("type"))){
            List<PvmTransition>pvmList= activityImpl.getOutgoingTransitions();
            for (int i=0;i<pvmList.size();i++) {
                currentMap=new HashMap<String, Object>();
                ActivityImpl activityImplXY=processDefinitionEntity.findActivity(pvmList.get(i).getDestination().getId());
                currentMap.put("x", activityImplXY.getX()); // x坐标
                currentMap.put("y", activityImplXY.getY()); // y坐标
                currentMap.put("width", activityImplXY.getWidth()); // 宽度
                currentMap.put("height", activityImplXY.getHeight()); // 高度
                currentList.add(currentMap);
            }

        }else{
            currentMap=new HashMap<String, Object>();
            currentMap.put("x", activityImpl.getX()); // x坐标
            currentMap.put("y", activityImpl.getY()); // y坐标
            currentMap.put("width", activityImpl.getWidth()); // 宽度
            currentMap.put("height", activityImpl.getHeight()); // 高度
            currentList.add(currentMap);
        }
        JSONArray jsonArray=JSONArray.parseArray(JSON.toJSONString(currentList));
        result.put("currentList", jsonArray);
        return CommonResult.success(result);

    }

    /**
     * 批注查询
     * @param map
     * @return
     * @throws Exception
     */
    @RequestMapping(value="/commentList",method = RequestMethod.POST)
    public CommonResult<JSONObject>  commentList(@RequestBody Map<String,Object> map)throws Exception{
        String processInstanceId=map.get("processInstanceId").toString();
        List<MyComment> commentList=new ArrayList<MyComment>();
        List<HistoricTaskInstance>  htiList=historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).list();
        Map<String,String> commentMap = getCommonList(processInstanceId);

        Map<String,String> userMap=userService.getUserList();
        for (HistoricTaskInstance hist:htiList) {
            MyComment myComment=new MyComment();
            myComment.setId(hist.getId());
            myComment.setName(hist.getName());
            myComment.setCreateTime(hist.getCreateTime());
            myComment.setEndTime(hist.getEndTime());
            myComment.setMemberName(userMap.get(hist.getAssignee()));
            myComment.setComment(commentMap.get(hist.getId()));
            commentList.add(myComment);
        }
        JSONObject result=new JSONObject();
        JSONArray jsonArray=JSONArray.parseArray(JSON.toJSONString(commentList,SerializerFeature.WriteNullStringAsEmpty));
        result.put("rows", jsonArray);
        return CommonResult.success(result);
    }

    /**
     *  审批
     * @param map
     * @return
     * @throws Exception
     */
    @RequestMapping(value="/audit",method = RequestMethod.POST)
    public CommonResult<JSONObject> audit(@RequestBody Map<String,Object> map)throws Exception{
        JSONObject result=new JSONObject();
        Map<String,Object> variables=new HashMap<String,Object>();
        String taskId=map.get("taskId").toString();
        String state=map.get("state").toString();
        String comment=map.get("comment").toString();
        String userId=map.get("userId").toString();
        String ids=map.get("ids").toString();
        // 根据任务id查询
        Task task=taskService.createTaskQuery().taskId(taskId).singleResult();
        // 获取流程实例id
        String processInstanceId=task.getProcessInstanceId();
        //2：获取流程定义ID
        String processDefinitionId = task.getProcessDefinitionId();
        //3：查询ProcessDefinitionEntiy对象
        ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(processDefinitionId);
        //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();

        //下一步为网关 设置流程变量
        if(map.containsKey("acKey")&&map.containsKey("elValue")){
            variables.put(map.get("acKey").toString(),map.get("elValue").toString());
        }
        //下一步为结束点(驳回)修改状态 放在任务完成之前
        if(map.containsKey("endEvent")||"3".equals(state)){
            result.put("endEvent", map.get("endEvent").toString());
            String url=taskService.getVariable(taskId,"url").toString();
            result.put("url",url);
        }
        // 设置批注用户
        Authentication.setAuthenticatedUserId(userId);
        // 添加批注信息
        taskService.addComment(taskId, processInstanceId, comment);
        // 完成任务
        taskService.complete(taskId, variables);

        //驳回
        if("3".equals(state)){
            runtimeService.deleteProcessInstance(processInstanceId,"驳回结束流程");
        }

        //批准
        if("2".equals(state)){
            //任务办理
            if(!map.containsKey("endEvent")){
                if(ElUtils.isNotBlank(ids)){
                    Map<String,String> mapUser= ElUtils.getStringToMap(ids);
                    // 根据流程实例Id查询任务
                    List<Task> taskNextList=taskService.createTaskQuery().processInstanceId(pi.getProcessInstanceId()).list();

                    for (Task taskNext : taskNextList) {
                        //设置下一审批人
                        if(!mapUser.containsKey("parallelGateway")){
                            taskService.setAssignee(taskNext.getId(),mapUser.get(taskNext.getTaskDefinitionKey()));
                        }else {
                            //并行网关特殊处理
                            taskService.setAssignee(taskNext.getId(),mapUser.get("parallelGateway"));
                        }

                    }

                }
            }
        }
        result.put("success", true);
        result.put("state",state);
        result.put("processInstanceId",processInstanceId);

        return CommonResult.success(result);
    }

    /**
     * 历史任务
     * @param page
     * @param limit
     * @param uid
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/historyTask",method = RequestMethod.GET)
    public CommonResult<JSONObject> historyTask(@RequestParam(value="page",defaultValue="0")String page, @RequestParam(value="limit",defaultValue="0")String limit,String uid,String finished)throws Exception{
        PageBean pageBean=new PageBean(Integer.parseInt(page),Integer.parseInt(limit));
        // 创建历史任务实例查询
        List<HistoricTaskInstance> htiList=null;
        long total=0;
        switch (finished){
            case "1":
                //已办任务
                htiList= historyService.createHistoricTaskInstanceQuery().orderByHistoricTaskInstanceEndTime().desc().taskAssignee(uid).unfinished().listPage(pageBean.getStart(), pageBean.getPageSize());
                total=historyService.createHistoricTaskInstanceQuery().taskAssignee(uid).unfinished().count();
                break;
            case "2":
                //历史任务
                htiList= historyService.createHistoricTaskInstanceQuery().orderByHistoricTaskInstanceEndTime().desc().taskAssignee(uid).finished().listPage(pageBean.getStart(), pageBean.getPageSize());
                total=historyService.createHistoricTaskInstanceQuery().taskAssignee(uid).finished().count();
                break;
            default:
                break;
        }
        List<MyTask> taskList=new ArrayList<MyTask>();
        Map<String,String> userMap=userService.getUserList();
        for(HistoricTaskInstance hti:htiList){
            MyTask myTask = new MyTask();
            myTask.setId(hti.getId());
            myTask.setProcessInstanceId(hti.getProcessInstanceId());
            myTask.setName(hti.getName());
            myTask.setCreateTime(hti.getCreateTime());
            myTask.setEndTime(hti.getEndTime());
            myTask.setUserName(userMap.get(hti.getAssignee()));
            taskList.add(myTask);
        }
        JSONObject result=new JSONObject();
        JSONArray jsonArray=JSONArray.parseArray(JSON.toJSONString(taskList,SerializerFeature.WriteNullStringAsEmpty));
        result.put("rows", jsonArray);
        result.put("total", total);
        return CommonResult.success(result);
    }

    /**
     * 根据任务id查询流程实例的具体执行过程
     * @param map
     * @return
     * @throws Exception
     */
    @RequestMapping(value="/listAction",method = RequestMethod.POST)
    public CommonResult<JSONObject> listAction(@RequestBody Map<String,Object> map)throws Exception{
        String taskId=map.get("taskId").toString();
        HistoricTaskInstance hti=historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
        // 获取流程实例id
        String processInstanceId=hti.getProcessInstanceId();
        List<HistoricActivityInstance> haiList=historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();

        JSONObject result=new JSONObject();
        JSONArray jsonArray=JSONArray.parseArray(JSON.toJSONString(haiList));
        result.put("rows", jsonArray);
        return CommonResult.success(result);
    }


    /**
     * 获取下一节点 设置审批人
     * @param map
     * @return
     * @throws Exception
     */
    @RequestMapping(value="/findActiviti",method = RequestMethod.POST)
    public CommonResult<JSONObject> findActiviti(@RequestBody Map<String,Object> map)throws Exception{
        JSONObject result=new JSONObject();

        List<Map<String, Object>> listName=new ArrayList<Map<String, Object>>();
        Map<String, Object> mapPv=null;
        List<PvmTransition> outTransitionsTemp=null;

        String taskId=map.get("taskId").toString();
        // 根据任务id查询
        Task task=taskService.createTaskQuery().taskId(taskId).singleResult();
        // 获取流程实例id
        String processInstanceId=task.getProcessInstanceId();
        //2：获取流程定义ID
        String processDefinitionId = task.getProcessDefinitionId();
        //3：查询ProcessDefinitionEntiy对象
        ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(processDefinitionId);
        //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        //获取当前活动的id
        String activityId = pi.getActivityId();
        //4：获取当前的活动
        List<ActivityImpl> activitiList = processDefinitionEntity.getActivities();
        for(ActivityImpl activityImpl:activitiList){
            if(activityId.equals(activityImpl.getId())) {
                //获取从某个节点出来的所有线路
                List<PvmTransition> outTransitions = activityImpl.getOutgoingTransitions();
                for(PvmTransition tr:outTransitions){
                    //获取线路的终点节点
                    PvmActivity ac = tr.getDestination();
                    switch (ac.getProperty("type").toString()){
                        case "userTask":
                            //普通节点
                            if("parallelGateway".equals(activityImpl.getProperty("type"))){
                                List<Task> taskNextList=taskService.createTaskQuery().processInstanceId(pi.getProcessInstanceId()).list();
                                if(taskNextList.size()==1){
                                    mapPv=new HashMap<String, Object>();
                                    mapPv.put("parallelGateway","");
                                    listName.add(mapPv);
                                }
                            }else{
                                mapPv=new HashMap<String, Object>();
                                mapPv.put(ac.getId(),ac.getProperty("name"));
                                listName.add(mapPv);
                            }
                            break;
                        case "exclusiveGateway":
                            outTransitionsTemp = ac.getOutgoingTransitions();
                            //网关线条只有多条才生效
                            if(outTransitionsTemp!=null&&outTransitionsTemp.size()>1){
                                for(PvmTransition exPvm : outTransitionsTemp){
                                    //获取排他网关线路判断条件信息
                                    String s = StringUtils.trim(exPvm.getProperty("conditionText").toString());
                                    //获取流程启动时设置的网关判断条件信息
                                    String elString=getGatewayCondition(ElUtils.getElString(s), processInstanceId);
                                    //判断el表达式是否成立
                                    if(isCondition(ElUtils.getElString(s), StringUtils.trim(s), elString)){
                                        result.put("acKey",ElUtils.getElString(s));
                                        result.put("elValue",elString);

                                        mapPv=new HashMap<String, Object>();
                                        mapPv.put(exPvm.getDestination().getId(),exPvm.getProperty("name"));
                                        listName.add(mapPv);
                                        break;
                                    }

                                }
                            }
                            break;
                        case "parallelGateway":
                            //并行网关
                            outTransitionsTemp = ac.getOutgoingTransitions();
                            for (PvmTransition tr1 : outTransitionsTemp) {
                                PvmActivity pv=tr1.getDestination();
                                mapPv=new HashMap<String, Object>();
                                mapPv.put(pv.getId(),pv.getProperty("name"));
                                listName.add(mapPv);
                            }

                            break;
                        case "endEvent":
                            //方便阅览 有此节点
                            break;
                        default:
                            //后续节点可按需增加
                            break;

                    }
                    result.put("pvmType",ac.getProperty("type"));
                    break;
                }
                break;
            }
        }
        result.put("listName",listName);
        return CommonResult.success(result);
    }

    /**
     * 获取流程Key
     * @param map
     * @return
     * @throws Exception
     */
    @RequestMapping(value="/getProcessInstanceKey",method = RequestMethod.POST)
    public CommonResult<JSONObject> getProcessInstanceKey(@RequestBody Map<String,Object> map)throws Exception{
        JSONObject result=new JSONObject();

        String procdef_id=map.get("procdef_id").toString();
        ProcessInstance pi = runtimeService.createProcessInstanceQuery()
                .processDefinitionId(procdef_id)
                .list().get(0);
        result.put("processInstanceKey",pi.getProcessDefinitionKey());
        result.put("success",true);
        return CommonResult.success(result);
    }

    /**
     * 查询流程启动时设置排他网关判断条件信息
     * @param  gatewayId          排他网关Id信息, 流程启动时设置网关路线判断条件key为网关Id信息
     * @param  processInstanceId  流程实例Id信息
     * @return
     */
    public String getGatewayCondition(String gatewayId, String processInstanceId) {
        Execution execution = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).singleResult();
        return runtimeService.getVariable(execution.getId(), gatewayId).toString();
    }

    /**
     * 根据key和value判断el表达式是否通过信息
     * @param  key    el表达式key信息
     * @param  el     el表达式信息
     * @param  value  el表达式传入值信息
     * @return
     */
    public boolean isCondition(String key, String el, String value) {
        ExpressionFactory factory = new ExpressionFactoryImpl();
        SimpleContext context = new SimpleContext();
        context.setVariable(key, factory.createValueExpression(value, String.class));
        ValueExpression e = factory.createValueExpression(context, el, boolean.class);
        return (Boolean) e.getValue(context);
    }

    /**
     * 获取流程模型列表
     * @return
     */
    public Map<String,String> getModelList(){
        Map<String,String>map=new HashMap<String, String>();
        List<Model> resultList=repositoryService.createModelQuery().list();
        for (Model model : resultList) {
            map.put(model.getKey(),model.getName());
        }
        return map;
    }

    /**
     * 流程实例ID获取批注信息
     * @param processInstanceId
     * @return
     */
    public Map<String,String> getCommonList(String processInstanceId){
        Map<String, String> map = new HashMap<String, String>();
        List<Comment> commentList=taskService.getProcessInstanceComments(processInstanceId);
        for (Comment comment : commentList) {
            map.put(comment.getTaskId(),comment.getFullMessage());
        }
        return map;
    }

}
